#include "test_scheme.h"
#include "context.h"
#include "evaluator_utils.h"
#include "numb.h"
#include "scheme.h"
#include "secret_key.h"
#include "string_utils.h"
#include "timer_utility.h"
#include <chrono>
#include <iostream>
#include <vector>

using namespace std;
using namespace chrono;

/* *
 * @brief ：测试编码、加密、解密和解码过程的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 */
void TestScheme::TestEncodeEncryptDecryptDecode(long logN, long L, long K, long T, long logSlots)
{
    cout << "!!! START TEST EncodeEncryptDecryptDecode !!!" << endl;
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    TimerUtility.Start("Gen SecretKey");
    SecretKey secretKey(context);
    TimerUtility.Stop("Gen SecretKey");
    Scheme scheme(secretKey, context);
    long slots = 1L << logSlots;
    uint64_t *mvec = new uint64_t[slots];
    EvaluatorUtils::RandomUint64Array(slots, mvec);
    Plaintext msg = scheme.Encode(mvec, slots, L);
    TimerUtility.Start("Encrypt PkEncrypt");
    Ciphertext cipher = scheme.EncryptMsg(msg);
    TimerUtility.Stop("Encrypt PkEncrypt");

    TimerUtility.Start("Decrypt Decrypt");
    msg = scheme.DecryptMsg(secretKey, cipher);
    TimerUtility.Stop("Decrypt Decrypt");
    uint64_t *dvec = scheme.Decode(msg);
    StringUtils::ShowCompare(mvec, dvec, 2, "EncodeEncryptDecryptDecode");
    cout << "!!! END TEST EncodeEncryptDecryptDecode !!!" << endl;
    delete []mvec;
    delete []dvec;
}

/* *
 * @brief ：测试编码、加密、解密和解码过程的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 * @param NUM_ITERATIONS ：测试轮次。
 */
void TestScheme::TestEncodeEncryptDecryptDecode(long logN, long L, long K, long T, long logSlots, int NUM_ITERATIONS)
{
    cout << "!!! START TEST EncodeEncryptDecryptDecode (100 iterations) !!!" << endl;
    
    double totalEncryptTime = 0.0;
    double totalDecryptTime = 0.0;
    
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    long slots = 1L << logSlots;
    
    for (int i = 0; i < NUM_ITERATIONS; i++) {
        uint64_t *mvec = new uint64_t[slots];
        EvaluatorUtils::RandomUint64Array(slots, mvec);
        Plaintext msg = scheme.Encode(mvec, slots, L);
        TimerUtility.Start("Encrypt PkEncrypt");
        Ciphertext cipher = scheme.EncryptMsg(msg);
        TimerUtility.Stop("Encrypt PkEncrypt");
        TimerUtility.Start("Encrypt EncodeEncrypt");

        TimerUtility.Start("Decrypt");
        msg = scheme.DecryptMsg(secretKey, cipher);
        TimerUtility.Stop("Decrypt");
        uint64_t *dvec = scheme.Decode(msg);
        totalDecryptTime += TimerUtility.GetTimeInterval();
        
        if (i == NUM_ITERATIONS - 1) {
            StringUtils::ShowCompare(mvec, dvec, 5, "EncodeEncryptDecryptDecode");
        }
        
        delete[] mvec;
        delete[] dvec;
    }
    
    double avgEncryptTime = totalEncryptTime / NUM_ITERATIONS;
    double avgDecryptTime = totalDecryptTime / NUM_ITERATIONS;
    
    cout << "\nAverage times over " << NUM_ITERATIONS << " iterations:" << endl;
    cout << "Average Encrypt EncodeEncrypt time = " << avgEncryptTime << " ms" << endl;
    cout << "Average Decrypt DecryptDecode time = " << avgDecryptTime << " ms" << endl;
    
    cout << "!!! END TEST EncodeEncryptDecryptDecode !!!" << endl;
}

/* *
 * @brief ：测试两个密文相乘并进行重新缩放的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 */
void TestScheme::TestMulCtCtWithReli(long logN, long L, long K, long T, long logSlots)
{
    cout << "!!! START TEST MultCtCtWithReli !!!" << endl;
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    long slots = (1 << logSlots);
    uint64_t *mvec1 = new uint64_t[slots];
    uint64_t *mvec2 = new uint64_t[slots];
    EvaluatorUtils::RandomUint64Array(slots, mvec1);
    EvaluatorUtils::RandomUint64Array(slots, mvec2);
    uint64_t *mvecMul = new uint64_t[slots];
    for (long i = 0; i < slots; i++) {
        mvecMul[i] = (mvec1[i] * mvec2[i]) % context.tVec[0];
    }
    Ciphertext cipher1 = scheme.Encrypt(mvec1, slots, L);
    Ciphertext cipher2 = scheme.Encrypt(mvec2, slots, L);

    Ciphertext multCipher(context.N, slots, L);
    TimerUtility.Start("MultCtCtWithReli");
    scheme.Mult(multCipher, cipher1, cipher2);
    // Ciphertext multCipher = scheme.Mult(cipher1, cipher2);
    TimerUtility.Stop("MultCtCtWithReli");
    uint64_t *dvecMul = scheme.Decrypt(secretKey, multCipher);
    StringUtils::ShowCompare(mvecMul, dvecMul, 2, "MultCtCtWithReli");
    cout << "!!! END TEST MultCtCtWithReli !!!" << endl;
}

/* *
 * @brief ：测试两个密文相乘并进行重新缩放的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 * @param NUM_ITERATIONS ：测试轮次。
 */
void TestScheme::TestMulCtCtWithReli(long logN, long L, long K, long T, long logSlots, int NUM_ITERATIONS)
{
    cout << "!!! START TEST MultCtCtWithReli (" << NUM_ITERATIONS << " iterations) !!!" << endl;
    
    double totalMultTime = 0.0;
    
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    long slots = (1 << logSlots);
    
    for (int iter = 0; iter < NUM_ITERATIONS; iter++) {
        // Generate new random data for each iteration
        uint64_t *mvec1 = new uint64_t[slots];
        uint64_t *mvec2 = new uint64_t[slots];
        EvaluatorUtils::RandomUint64Array(slots, mvec1);
        EvaluatorUtils::RandomUint64Array(slots, mvec2);
        
        uint64_t *mvecMul = new uint64_t[slots];
        for (long i = 0; i < slots; i++) {
            mvecMul[i] = (mvec1[i] * mvec2[i]) % context.tVec[0];
        }
        
        Ciphertext cipher1 = scheme.Encrypt(mvec1, slots, L);
        Ciphertext cipher2 = scheme.Encrypt(mvec2, slots, L);
        Ciphertext multCipher(context.N, slots, L);
        TimerUtility.Start("MultCtCtWithReli");
        scheme.Mult(multCipher, cipher1, cipher2);
        TimerUtility.Stop("MultCtCtWithReli");
        totalMultTime += TimerUtility.GetTimeInterval();
        
        uint64_t *dvecMul = scheme.Decrypt(secretKey, multCipher);
        
        // Only show comparison for the last iteration
        if (iter == NUM_ITERATIONS - 1) {
            StringUtils::ShowCompare(mvecMul, dvecMul, 5, "MultCtCtWithReli");
        }
        
        // Clean up memory
        delete[] mvec1;
        delete[] mvec2;
        delete[] mvecMul;
        delete[] dvecMul;
    }
    
    double avgMultTime = totalMultTime / NUM_ITERATIONS;
    
    cout << "\nAverage times over " << NUM_ITERATIONS << " iterations:" << endl;
    cout << "Average MultCtCtWithReli time = " << avgMultTime << " ms" << endl;
    
    cout << "!!! END TEST MultCtCtWithReli !!!" << endl;
}

/* *
 * @brief ：测试密文与明文相乘的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 */
void TestScheme::TestMultCtPt(long logN, long L, long K, long T, long logSlots)
{
    cout << "!!! START TEST MultCtPt !!!" << endl;
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    long slots = (1 << logSlots);
    uint64_t *mvec1 = new uint64_t[slots];
    uint64_t *mvec2 = new uint64_t[slots];
    EvaluatorUtils::RandomUint64Array(slots, mvec1);
    EvaluatorUtils::RandomUint64Array(slots, mvec2);
    uint64_t *mvecMul = new uint64_t[slots];
    for (long i = 0; i < slots; i++) {
        mvecMul[i] = (mvec1[i] * mvec2[i]) % context.tVec[0];
    }
    Ciphertext cipher = scheme.Encrypt(mvec1, slots, L);
    Plaintext plaintext = scheme.Encode(mvec2, slots, L);
    TimerUtility.Start("MultCtPt");
    Ciphertext multCipher = scheme.MultPt(cipher, plaintext);
    TimerUtility.Stop("MultCtPt");
    uint64_t *dvecMul = scheme.Decrypt(secretKey, multCipher);
    StringUtils::ShowCompare(mvecMul, dvecMul, 5, "MultCtPt");
    cout << "!!! END TEST MultCtPt !!!" << endl;
}

/* *
 * @brief ：测试密文与明文相乘的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 * @param NUM_ITERATIONS ：测试轮次。
 */
void TestScheme::TestMultCtPt(long logN, long L, long K, long T, long logSlots, int NUM_ITERATIONS)
{
    cout << "!!! START TEST MultCtPt (" << NUM_ITERATIONS << " iterations) !!!" << endl;
    
    double totalMultTime = 0.0;
    
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    long slots = (1 << logSlots);
    
    for (int iter = 0; iter < NUM_ITERATIONS; iter++) {
        // Generate new random data for each iteration
        uint64_t *mvec1 = new uint64_t[slots];
        uint64_t *mvec2 = new uint64_t[slots];
        EvaluatorUtils::RandomUint64Array(slots, mvec1);
        EvaluatorUtils::RandomUint64Array(slots, mvec2);
        
        uint64_t *mvecMul = new uint64_t[slots];
        for (long i = 0; i < slots; i++) {
            mvecMul[i] = (mvec1[i] * mvec2[i]) % context.tVec[0];
        }
        
        Ciphertext cipher = scheme.Encrypt(mvec1, slots, L);
        Plaintext plaintext = scheme.Encode(mvec2, slots, L);
        
        TimerUtility.Start("MultCtPt");
        Ciphertext multCipher = scheme.MultPt(cipher, plaintext);
        TimerUtility.Stop("MultCtPt");
        totalMultTime += TimerUtility.GetTimeInterval();
        
        uint64_t *dvecMul = scheme.Decrypt(secretKey, multCipher);
        
        // Only show comparison for the last iteration
        if (iter == NUM_ITERATIONS - 1) {
            StringUtils::ShowCompare(mvecMul, dvecMul, 5, "MultCtPt");
        }
        
        // Clean up memory
        delete[] mvec1;
        delete[] mvec2;
        delete[] mvecMul;
        delete[] dvecMul;
    }
    
    double avgMultTime = totalMultTime / NUM_ITERATIONS;
    
    cout << "\nAverage times over " << NUM_ITERATIONS << " iterations:" << endl;
    cout << "Average MultCtPt time = " << avgMultTime << " ms" << endl;
    
    cout << "!!! END TEST MultCtPt !!!" << endl;
}

/* *
 * @brief ：测试多次密文相乘的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 */
void TestScheme::TestMultRepeat(long logN, long L, long K, long T, long logSlots)
{
    cout << "!!! START TEST MULT REPEAT !!!" << endl;
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    long slots = (1 << logSlots);
    uint64_t *mvec1 = new uint64_t[slots];
    uint64_t *mvec2 = new uint64_t[slots];
    EvaluatorUtils::RandomUint64Array(slots, mvec1);
    EvaluatorUtils::RandomUint64Array(slots, mvec2);
    uint64_t *mvecMult = new uint64_t[slots];
    int times = L - 2;
    cout<<"times: "<<times<<endl;
    for (long i = 0; i < slots; i++) {
        mvecMult[i] = (mvec1[i] * mvec2[i]) % context.tVec[0];
    }
    for (int j = 0; j < times; j++) {
        for (long i = 0; i < slots; i++) {
            mvecMult[i] = (mvecMult[i] * mvec2[i]) % context.tVec[0];
        }
    }
    TimerUtility.Start("Encrypt two batch");
    Ciphertext cipher1 = scheme.Encrypt(mvec1, slots, L);
    Ciphertext cipher2 = scheme.Encrypt(mvec2, slots, L);
    TimerUtility.Stop("Encrypt two batch");

    TimerUtility.Start("Homomorphic Multiplication & Rescaling");
    Ciphertext multCipher = scheme.Mult(cipher1, cipher2);
    TimerUtility.Stop("Homomorphic Multiplication & Rescaling");

    for (int i = 0; i < times; i++) {
        TimerUtility.Start("Homomorphic Multiplication & Rescaling");
        multCipher = scheme.Mult(multCipher, cipher2);
        TimerUtility.Stop("Homomorphic Multiplication & Rescaling");
    }
    TimerUtility.Start("Decrypt batch");
    uint64_t *dvecMult = scheme.Decrypt(secretKey, multCipher);
    TimerUtility.Stop("Decrypt batch");
    StringUtils::ShowCompare(mvecMult, dvecMult, 5, "mult");
    cout << "!!! END TEST MULT REPEAT !!!" << endl;
}

/* *
 * @brief ：测试两个密文相加的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 */
void TestScheme::TestAddCtCt(long logN, long L, long K, long T, long logSlots)
{
    cout << "!!! START TEST AddCtCt !!!" << endl;
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    long slots = (1 << logSlots);
    uint64_t *mvec1 = new uint64_t[slots];
    uint64_t *mvec2 = new uint64_t[slots];
    EvaluatorUtils::RandomUint64Array(slots, mvec1);
    EvaluatorUtils::RandomUint64Array(slots, mvec2);
    uint64_t *mvecAdd = new uint64_t[slots];
    for (long i = 0; i < slots; i++) {
        mvecAdd[i] = (mvec1[i] + mvec2[i]) % context.tVec[0];
    }
    Ciphertext cipher1 = scheme.Encrypt(mvec1, slots, L);
    Ciphertext cipher2 = scheme.Encrypt(mvec2, slots, L);
    // Ciphertext addCipher = Ciphertext(context.N, slots, L);
    TimerUtility.Start("AddCtCt");
    Ciphertext addCipher = scheme.Add(cipher1, cipher2);
    TimerUtility.Stop("AddCtCt");
    uint64_t *dvecMul = scheme.Decrypt(secretKey, addCipher);
    StringUtils::ShowCompare(mvecAdd, dvecMul, 5, "AddCtCt");
    cout << "!!! END TEST AddCtCt !!!" << endl;
}

/* *
 * @brief ：测试两个密文相加的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 * @param NUM_ITERATIONS ：测试轮次。
 */
void TestScheme::TestAddCtCt(long logN, long L, long K, long T, long logSlots, int NUM_ITERATIONS)
{
    cout << "!!! START TEST AddCtCt (" << NUM_ITERATIONS << " iterations) !!!" << endl;
    
    double totalAddTime = 0.0;
    
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    long slots = (1 << logSlots);
    
    for (int iter = 0; iter < NUM_ITERATIONS; iter++) {
        // Generate new random data for each iteration
        uint64_t *mvec1 = new uint64_t[slots];
        uint64_t *mvec2 = new uint64_t[slots];
        EvaluatorUtils::RandomUint64Array(slots, mvec1);
        EvaluatorUtils::RandomUint64Array(slots, mvec2);
        
        uint64_t *mvecAdd = new uint64_t[slots];
        for (long i = 0; i < slots; i++) {
            mvecAdd[i] = (mvec1[i] + mvec2[i]) % context.tVec[0];
        }
        
        Ciphertext cipher1 = scheme.Encrypt(mvec1, slots, L);
        Ciphertext cipher2 = scheme.Encrypt(mvec2, slots, L);
        
        TimerUtility.Start("AddCtCt");
        Ciphertext addCipher = scheme.Add(cipher1, cipher2);
        TimerUtility.Stop("AddCtCt");
        totalAddTime += TimerUtility.GetTimeInterval();
        
        uint64_t *dvecAdd = scheme.Decrypt(secretKey, addCipher);
        
        // Only show comparison for the last iteration
        if (iter == NUM_ITERATIONS - 1) {
            StringUtils::ShowCompare(mvecAdd, dvecAdd, 5, "AddCtCt");
        }
        
        // Clean up memory
        delete[] mvec1;
        delete[] mvec2;
        delete[] mvecAdd;
        delete[] dvecAdd;
    }
    
    double avgAddTime = totalAddTime / NUM_ITERATIONS;
    
    cout << "\nAverage times over " << NUM_ITERATIONS << " iterations:" << endl;
    cout << "Average AddCtCt time = " << avgAddTime << " ms" << endl;
    
    cout << "!!! END TEST AddCtCt !!!" << endl;
}

/* *
 * @brief ：测试密文与明文相加的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 */
void TestScheme::TestAddCtPt(long logN, long L, long K, long T, long logSlots)
{
    cout << "!!! START TEST AddCtPt !!!" << endl;
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    long slots = (1 << logSlots);
    uint64_t *mvec1 = new uint64_t[slots];
    uint64_t *mvec2 = new uint64_t[slots];
    EvaluatorUtils::RandomUint64Array(slots, mvec1);
    EvaluatorUtils::RandomUint64Array(slots, mvec2);
    uint64_t *mvecAdd = new uint64_t[slots];
    for (long i = 0; i < slots; i++) {
        mvecAdd[i] = (mvec1[i] + mvec2[i]) % context.tVec[0];
    }
    Ciphertext cipher = scheme.Encrypt(mvec1, slots, L);
    Plaintext plaintext = scheme.Encode(mvec2, slots, L);
    TimerUtility.Start("AddCtPt");
    Ciphertext addCipher = scheme.AddPt(cipher, plaintext);
    TimerUtility.Stop("AddCtPt");
    uint64_t *dvecAdd = scheme.Decrypt(secretKey, addCipher);
    StringUtils::ShowCompare(mvecAdd, dvecAdd, 5, "AddCtPt");
    cout << "!!! END TEST AddCtPt !!!" << endl;
}

/* *
 * @brief ：测试密文与明文相加的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 * @param NUM_ITERATIONS ：测试轮次。
 */
void TestScheme::TestAddCtPt(long logN, long L, long K, long T, long logSlots, int NUM_ITERATIONS)
{
    cout << "!!! START TEST AddCtPt (" << NUM_ITERATIONS << " iterations) !!!" << endl;
    
    double totalAddTime = 0.0;
    
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    long slots = (1 << logSlots);
    
    for (int iter = 0; iter < NUM_ITERATIONS; iter++) {
        // Generate new random data for each iteration
        uint64_t *mvec1 = new uint64_t[slots];
        uint64_t *mvec2 = new uint64_t[slots];
        EvaluatorUtils::RandomUint64Array(slots, mvec1);
        EvaluatorUtils::RandomUint64Array(slots, mvec2);
        
        uint64_t *mvecAdd = new uint64_t[slots];
        for (long i = 0; i < slots; i++) {
            mvecAdd[i] = (mvec1[i] + mvec2[i]) % context.tVec[0];
        }
        
        Ciphertext cipher = scheme.Encrypt(mvec1, slots, L);
        Plaintext plaintext = scheme.Encode(mvec2, slots, L);
        
        TimerUtility.Start("AddCtPt");
        Ciphertext addCipher = scheme.AddPt(cipher, plaintext);
        TimerUtility.Stop("AddCtPt");
        totalAddTime += TimerUtility.GetTimeInterval();
        
        uint64_t *dvecAdd = scheme.Decrypt(secretKey, addCipher);
        
        // Only show comparison for the last iteration
        if (iter == NUM_ITERATIONS - 1) {
            StringUtils::ShowCompare(mvecAdd, dvecAdd, 5, "AddCtPt");
        }
        
        // Clean up memory
        delete[] mvec1;
        delete[] mvec2;
        delete[] mvecAdd;
        delete[] dvecAdd;
    }
    
    double avgAddTime = totalAddTime / NUM_ITERATIONS;
    
    cout << "\nAverage times over " << NUM_ITERATIONS << " iterations:" << endl;
    cout << "Average AddCtPt time = " << avgAddTime << " ms" << endl;
    
    cout << "!!! END TEST AddCtPt !!!" << endl;
}

/* *
 * @brief ：测试批量旋转操作的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param rotSlots ：旋转的插槽数量。
 * @param logSlots ：插槽的对数数量。
 * @param isLeft ：布尔值，指示是左旋转还是右旋转。
 */
void TestScheme::TestRotateBatch(long logN, long L, long K, long T, long rotSlots, long logSlots, bool isLeft)
{
    cout << "!!! START TEST ROTATE !!!" << endl;
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    long slots = 1 << logSlots;
    uint64_t *mvec = new uint64_t[slots];
    EvaluatorUtils::RandomUint64Array(slots, mvec);
    Ciphertext cipher = scheme.Encrypt(mvec, slots, L);
    

    if(isLeft){
        TimerUtility.Start("生成旋转密钥");
        scheme.AddLeftRotKey(secretKey, rotSlots);
        TimerUtility.Stop("生成旋转密钥");

        TimerUtility.Start("Left rotate batch");
        scheme.LeftRotateAndEqual(cipher, rotSlots);
        TimerUtility.Stop("Left rotate batch");
        uint64_t *dvec = scheme.Decrypt(secretKey, cipher);
        EvaluatorUtils::LeftRotateAndEqual(mvec, slots, rotSlots);
        StringUtils::ShowCompare(mvec, dvec, 5, "rot");
    }
    else {
        TimerUtility.Start("生成旋转密钥");
        scheme.AddLeftRotKey(secretKey, context.Nh - rotSlots);
        TimerUtility.Stop("生成旋转密钥");
        TimerUtility.Start("Right rotate batch");
        scheme.RightRotateAndEqual(cipher, rotSlots);
        TimerUtility.Stop("Right rotate batch");
        uint64_t *dvec = scheme.Decrypt(secretKey, cipher);
        EvaluatorUtils::RightRotateAndEqual(mvec, slots, rotSlots);
        // EvaluatorUtils::RightRotateAndEqual(mvec, slots / 2, rotSlots);
        // EvaluatorUtils::RightRotateAndEqual(mvec + slots / 2, slots / 2, rotSlots);
        StringUtils::ShowCompare(mvec, dvec, 5, "rot");
    }
    
    cout << "!!! END TEST ROTATE !!!" << endl;
}

/* *
 * @brief ：测试批量旋转操作的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param rotSlots ：旋转的插槽数量。
 * @param logSlots ：插槽的对数数量。
 * @param isLeft ：布尔值，指示是左旋转还是右旋转。
 * @param NUM_ITERATIONS ：测试轮次。
 */
void TestScheme::TestRotateBatch(long logN, long L, long K, long T, long rotSlots, long logSlots, bool isLeft, int NUM_ITERATIONS)
{
    cout << "!!! START TEST ROTATE (" << NUM_ITERATIONS << " iterations) !!!" << endl;
    
    double totalRotateTime = 0.0;
    
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    
    // Add rotation keys once, outside the loop since they don't change
    if (isLeft) {
        scheme.AddLeftRotKeys(secretKey);
    } else {
        scheme.AddRightRotKeys(secretKey);
    }
    
    long slots = (1 << logSlots);
    
    for (int iter = 0; iter < NUM_ITERATIONS; iter++) {
        // Generate new random data for each iteration
        uint64_t *mvec = new uint64_t[slots];
        EvaluatorUtils::RandomUint64Array(slots, mvec);
        
        Ciphertext cipher = scheme.Encrypt(mvec, slots, L);
        
        if (isLeft) {
            TimerUtility.Start("Left rotate batch");
            scheme.LeftRotateAndEqual(cipher, rotSlots);
            TimerUtility.Stop("Left rotate batch");
        } else {
            TimerUtility.Start("Right rotate batch");
            scheme.RightRotateAndEqual(cipher, rotSlots);
            TimerUtility.Stop("Right rotate batch");
        }
        totalRotateTime += TimerUtility.GetTimeInterval();
        
        uint64_t *dvec = scheme.Decrypt(secretKey, cipher);
    
        if (isLeft) {
            EvaluatorUtils::LeftRotateAndEqual(mvec, slots, rotSlots);
        } else {
            EvaluatorUtils::RightRotateAndEqual(mvec, slots, rotSlots);
        }
        
        // Only show comparison for the last iteration
        if (iter == NUM_ITERATIONS - 1) {
            StringUtils::ShowCompare(mvec, dvec, slots, "rot");
        }
        
        // Clean up memory
        delete[] mvec;
        delete[] dvec;
    }
    
    double avgRotateTime = totalRotateTime / NUM_ITERATIONS;
    
    cout << "\nAverage times over " << NUM_ITERATIONS << " iterations:" << endl;
    cout << "Average " << (isLeft ? "Left" : "Right") << " rotate time = " << avgRotateTime << " ms" << endl;
    
    cout << "!!! END TEST ROTATE !!!" << endl;
}

/* *
 * @brief ：测试列旋转操作的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 */
void TestScheme::TestRotateColumn(long logN, long L, long K, long T, long logSlots)
{
    cout << "!!! START TEST ROTATE COLUMN !!!" << endl;
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    scheme.AddLeftRotKey(secretKey, 0);
    long slots = (1 << logSlots);
    uint64_t *mvec = new uint64_t[slots];
    EvaluatorUtils::RandomUint64Array(slots, mvec);
    Ciphertext cipher = scheme.Encrypt(mvec, slots, L);
    TimerUtility.Start("Column rotate");
    scheme.LeftRotateAndEqualFast(cipher, 0);
    TimerUtility.Stop("Column rotate");
    uint64_t *dvec = scheme.Decrypt(secretKey, cipher);
    EvaluatorUtils::RotateColumnAndEqual(mvec, slots);
    StringUtils::ShowCompare(mvec, dvec, 5, "rot");
    cout << "!!! END TEST ROTATE COLUMN !!!" << endl;
}

/* *
 * @brief ：测试列旋转操作的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 * @param NUM_ITERATIONS ：测试轮次。
 */
void TestScheme::TestRotateColumn(long logN, long L, long K, long T, long logSlots, int NUM_ITERATIONS)
{
    cout << "!!! START TEST ROTATE COLUMN (" << NUM_ITERATIONS << " iterations) !!!" << endl;
    
    double totalRotateTime = 0.0;
    
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    
    // Add rotation key once, outside the loop since it doesn't change
    scheme.AddLeftRotKey(secretKey, 0);
    
    long slots = (1 << logSlots);
    
    for (int iter = 0; iter < NUM_ITERATIONS; iter++) {
        // Generate new random data for each iteration
        uint64_t *mvec = new uint64_t[slots];
        EvaluatorUtils::RandomUint64Array(slots, mvec);
        
        Ciphertext cipher = scheme.Encrypt(mvec, slots, L);
        
        TimerUtility.Start("Column rotate");
        scheme.LeftRotateAndEqualFast(cipher, 0);
        TimerUtility.Stop("Column rotate");
        totalRotateTime += TimerUtility.GetTimeInterval();
        
        uint64_t *dvec = scheme.Decrypt(secretKey, cipher);
        
        // Apply rotation to original vector for comparison
        EvaluatorUtils::RotateColumnAndEqual(mvec, slots);
        
        // Only show comparison for the last iteration
        if (iter == NUM_ITERATIONS - 1) {
            StringUtils::ShowCompare(mvec, dvec, 5, "rot");
        }
        
        // Clean up memory
        delete[] mvec;
        delete[] dvec;
    }
    
    double avgRotateTime = totalRotateTime / NUM_ITERATIONS;
    
    cout << "\nAverage times over " << NUM_ITERATIONS << " iterations:" << endl;
    cout << "Average Column rotate time = " << avgRotateTime << " ms" << endl;
    
    cout << "!!! END TEST ROTATE COLUMN !!!" << endl;
}

/* *
 * @brief ：测试密钥生成的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 */
void TestScheme::TestKeyGeneration(long logN, long L, long K, long T, long logSlots)
{
    cout << "!!! START TEST KEYS !!!" << endl;
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    TimerUtility.Start("secretKey");
    SecretKey secretKey(context);
    TimerUtility.Stop("secretKey");
    Scheme scheme(secretKey, context);
    TimerUtility.Start("rotatekey");
    scheme.AddLeftRotKey(secretKey, 0);
    TimerUtility.Stop("rotatekey");
    cout << "!!! END TEST KEYS !!!" << endl;
}

/* *
 * @brief ：测试密钥生成的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 * @param NUM_ITERATIONS ：测试轮次。
 */
void TestScheme::TestSecretKeyGeneration(long logN, long L, long K, long T, long logSlots, int NUM_ITERATIONS)
{
    cout << "!!! START TEST SECRET KEY GENERATION (" << NUM_ITERATIONS << " iterations) !!!" << endl;
    
    double totalKeyGenTime = 0.0;
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    
    for (int iter = 0; iter < NUM_ITERATIONS; iter++) {
        TimerUtility.Start("secretKey");
        SecretKey secretKey(context);
        TimerUtility.Stop("secretKey");
        totalKeyGenTime += TimerUtility.GetTimeInterval();
    }
    
    double avgKeyGenTime = totalKeyGenTime / NUM_ITERATIONS;
    
    cout << "\nAverage times over " << NUM_ITERATIONS << " iterations:" << endl;
    cout << "Average Secret Key Generation time = " << avgKeyGenTime << " ms" << endl;
    
    cout << "!!! END TEST SECRET KEY GENERATION !!!" << endl;
}

/* *
 * @brief ：测试密钥生成的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 * @param NUM_ITERATIONS ：测试轮次。
 */
void TestScheme::TestRotateKeyGeneration(long logN, long L, long K, long T, long logSlots, int NUM_ITERATIONS)
{
    cout << "!!! START TEST ROTATE KEY GENERATION (" << NUM_ITERATIONS << " iterations) !!!" << endl;
    
    double totalRotKeyGenTime = 0.0;
    TimerUtility  TimerUtility ;
    
    // Create context and secret key once, outside the loop
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    
    for (int iter = 0; iter < NUM_ITERATIONS; iter++) {
        // Create new scheme for each iteration to ensure fresh state
        Scheme scheme(secretKey, context);
        
        TimerUtility.Start("rotatekey");
        scheme.AddLeftRotKey(secretKey, 0);
        TimerUtility.Stop("rotatekey");
        totalRotKeyGenTime += TimerUtility.GetTimeInterval();
    }
    
    double avgRotKeyGenTime = totalRotKeyGenTime / NUM_ITERATIONS;
    
    cout << "\nAverage times over " << NUM_ITERATIONS << " iterations:" << endl;
    cout << "Average Rotate Key Generation time = " << avgRotKeyGenTime << " ms" << endl;
    
    cout << "!!! END TEST ROTATE KEY GENERATION !!!" << endl;
}

/* *
 * @brief ：测试私钥加解密过程的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 */
void TestScheme::TestEncryptBySecretKey(long logN, long L, long K, long T, long logSlots)
{
    cout << "!!! START TEST Encrypt By Secret Key !!!" << endl;
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    long slots = 1L << logSlots;
    uint64_t *mvec = new uint64_t[slots];
    EvaluatorUtils::RandomUint64Array(slots, mvec);
    Plaintext msg = scheme.Encode(mvec, slots, L);
    TimerUtility.Start("Encrypt By Secret Key");
    Ciphertext cipher = scheme.EncryptMsg(secretKey, msg);
    TimerUtility.Stop("Encrypt By Secret Key");
    TimerUtility.Start("Decrypt DecryptDecode");
    uint64_t *dvec = scheme.Decrypt(secretKey, cipher);
    StringUtils::ShowCompare(mvec, dvec, 2, "EncodeEncryptDecryptDecode");
    TimerUtility.Stop("Decrypt DecryptDecode");
    cout << "!!! END TEST EncodeEncryptDecryptDecode !!!" << endl;
}

/* *
 * @brief ：测试私钥加解密过程的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 * @param NUM_ITERATIONS ：测试轮次。
 * 
 */
void TestScheme::TestEncryptBySecretKey(long logN, long L, long K, long T, long logSlots, int NUM_ITERATIONS)
{
    cout << "!!! START TEST Encrypt By Secret Key (" << NUM_ITERATIONS << " iterations) !!!" << endl;
    
    double totalEncryptTime = 0.0;
    
    TimerUtility  TimerUtility ;
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    Scheme scheme(secretKey, context);
    long slots = 1L << logSlots;
    
    for (int iter = 0; iter < NUM_ITERATIONS; iter++) {
        // Generate new random data for each iteration
        uint64_t *mvec = new uint64_t[slots];
        EvaluatorUtils::RandomUint64Array(slots, mvec);
        
        TimerUtility.Start("Encrypt By Secret Key");
        Ciphertext cipher = scheme.EncryptBySk(mvec, slots, L, secretKey);
        TimerUtility.Stop("Encrypt By Secret Key");
        totalEncryptTime += TimerUtility.GetTimeInterval();
        
        uint64_t *dvec = scheme.Decrypt(secretKey, cipher);
        
        // Only show comparison for the last iteration
        if (iter == NUM_ITERATIONS - 1) {
            StringUtils::ShowCompare(mvec, dvec, 5, "EncryptBySecretKey");
        }
        
        // Clean up memory
        delete[] mvec;
        delete[] dvec;
    }
    
    double avgEncryptTime = totalEncryptTime / NUM_ITERATIONS;
    
    cout << "\nAverage times over " << NUM_ITERATIONS << " iterations:" << endl;
    cout << "Average Encrypt By Secret Key time = " << avgEncryptTime << " ms" << endl;
    
    cout << "!!! END TEST EncryptBySecretKey !!!" << endl;
}

/* *
 * @brief ：测试密钥生成的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 * @param NUM_ITERATIONS ：测试轮次。
 */


/* *
 * @brief ：测试密钥生成的函数
 *
 * @param logN ：多项式的对数阶数。
 * @param L ：参数 L，用于加密方案的设置。
 * @param K ：参数 K，用于加密方案的设置。
 * @param T ：模数 T，用于加密方案的设置。
 * @param logSlots ：插槽的对数数量。
 * @param NUM_ITERATIONS ：测试轮次。
 */
void TestScheme::TestPublicKeyGen(long logN, long L, long K, long T, long logSlots, int NUM_ITERATIONS)
{
    cout << "!!! START TEST PUBLIC KEY GENERATION (" << NUM_ITERATIONS << " iterations) !!!" << endl;
    
    double totalPubKeyTime = 0.0;
    TimerUtility  TimerUtility ;
    
    // Create context and secret key once
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    
    // Create test scheme once
    TestSchemeKeyGen testScheme(context);
    
    for (int iter = 0; iter < NUM_ITERATIONS; iter++) {
        TimerUtility.Start("Public Key");
        testScheme.GenerateEncKey(secretKey);
        TimerUtility.Stop("Public Key");
        totalPubKeyTime += TimerUtility.GetTimeInterval();
    }
    
    double avgPubKeyTime = totalPubKeyTime / NUM_ITERATIONS;
    
    cout << "\nAverage times over " << NUM_ITERATIONS << " iterations:" << endl;
    cout << "Average Public Key Generation time = " << avgPubKeyTime << " ms" << endl;
    
    cout << "!!! END TEST PUBLIC KEY GENERATION !!!" << endl;
}

void TestScheme::TestSwitchKeyGen(long logN, long L, long K, long T, long logSlots, int NUM_ITERATIONS)
{
    cout << "!!! START TEST SWITCH KEY GENERATION (" << NUM_ITERATIONS << " iterations) !!!" << endl;
    
    double totalSwitchKeyTime = 0.0;
    TimerUtility  TimerUtility ;
    
    // Create context and secret key once
    Context context(logN, L, K, T);
    SecretKey secretKey(context);
    
    // Create test scheme once
    TestSchemeKeyGen testScheme(context);
    
    for (int iter = 0; iter < NUM_ITERATIONS; iter++) {
        TimerUtility.Start("Switch Key");
        testScheme.GenerateMultKey(secretKey);
        TimerUtility.Stop("Switch Key");
        totalSwitchKeyTime += TimerUtility.GetTimeInterval();
    }
    
    double avgSwitchKeyTime = totalSwitchKeyTime / NUM_ITERATIONS;
    
    cout << "\nAverage times over " << NUM_ITERATIONS << " iterations:" << endl;
    cout << "Average Switch Key Generation time = " << avgSwitchKeyTime << " ms" << endl;
    
    cout << "!!! END TEST SWITCH KEY GENERATION !!!" << endl;
}